
#include "bsp.h"


/***************************************************************************************************
 * @fn      get_tim_rcc
 *
 * @brief   获取定时器的RCC初始化值
 *
 * @param   tim 定时器地址编号
 *
 * @return  定时器的RCC初始化值 
 */
rcu_periph_enum get_tim_rcc(uint32_t tim)
{
    rcu_periph_enum rcc;
    
    if (TIMER0 == tim)
    {
        rcc = RCU_TIMER0;
    }
    else if (TIMER1 == tim)
    {
        rcc = RCU_TIMER1;
    }
    else if (TIMER2 == tim)
    {
        rcc = RCU_TIMER2;
    }
    else if (TIMER3 == tim)
    {
        rcc = RCU_TIMER3;
    }
    else if (TIMER4 == tim)
    {
        rcc = RCU_TIMER4;
    }
    else if (TIMER5 == tim)
    {
        rcc = RCU_TIMER5;
    }
    else if (TIMER6 == tim)
    {
        rcc = RCU_TIMER6;
    }
    else if (TIMER7 == tim)
    {
        rcc = RCU_TIMER7;
    }
    else if (TIMER8 == tim)
    {
        rcc = RCU_TIMER8;
    }
    else if (TIMER9 == tim)
    {
        rcc = RCU_TIMER9;
    }
    else if (TIMER10 == tim)
    {
        rcc = RCU_TIMER10;
    }
    else if (TIMER11 == tim)
    {
        rcc = RCU_TIMER11;
    }
    else if (TIMER12 == tim)
    {
        rcc = RCU_TIMER12;
    }
    else if (TIMER13 == tim)
    {
        rcc = RCU_TIMER13;
    }
    
    return rcc;
}

/***************************************************************************************************
 * @fn      get_gpio_rcc
 *
 * @brief   获取GPIO的RCC初始化值
 *
 * @param   gpio_port GPIO端口地址编号
 *
 * @return  GPIO的RCC初始化值 
 */
rcu_periph_enum get_gpio_rcc(uint32_t gpio_port)
{
    rcu_periph_enum rcc;

    if (GPIOA == gpio_port)
    {
        rcc = RCU_GPIOA;
    }
    else if (GPIOB == gpio_port)
    {
        rcc = RCU_GPIOB;
    }
    else if (GPIOC == gpio_port)
    {
        rcc = RCU_GPIOC;
    }
    else if (GPIOD == gpio_port)
    {
        rcc = RCU_GPIOD;
    }
    else if (GPIOE == gpio_port)
    {
        rcc = RCU_GPIOE;
    }
    else if (GPIOF == gpio_port)
    {
        rcc = RCU_GPIOF;
    }
    else if (GPIOG == gpio_port)
    {
        rcc = RCU_GPIOG;
    }
    else if (GPIOH == gpio_port)
    {
        rcc = RCU_GPIOH;
    }
    else if (GPIOI == gpio_port)
    {
        rcc = RCU_GPIOI;
    }

    return rcc;
}

/***************************************************************************************************
 * @fn      config_gpio_pwm
 *
 * @brief   把GPIO配置成pwm输出的模式
 *
 * @param   gpio GPIO配置信息
 *
 * @return  无 
 */
static void config_gpio_pwm(pwm_gpio_t *gpio)
{
    rcu_periph_clock_enable(get_gpio_rcc(gpio->gpio_port));
    
    /*Configure GPIO as alternate function*/
    gpio_mode_set(gpio->gpio_port, GPIO_MODE_AF, GPIO_PUPD_NONE, gpio->gpio_pin);
    gpio_output_options_set(gpio->gpio_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, gpio->gpio_pin);

    gpio_af_set(gpio->gpio_port, gpio->gpio_af, gpio->gpio_pin); 
}

/***************************************************************************************************
 * @fn      config_gpio_output
 *
 * @brief   把GPIO配置成通用的推挽输出模式
 *
 * @param   gpio GPIO配置信息
 *
 * @return  无 
 */
static void config_gpio_output(pwm_gpio_t *gpio)
{
    rcu_periph_clock_enable(get_gpio_rcc(gpio->gpio_port));
    
    /*Configure GPIO as alternate function*/
    gpio_mode_set(gpio->gpio_port, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, gpio->gpio_pin);
    gpio_output_options_set(gpio->gpio_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, gpio->gpio_pin);
}

/***************************************************************************************************
 * @fn      timer_enable_cmd
 *
 * @brief   使能定时器命令
 *
 * @param   tim_n 定时器编号
 * @param   enable ENABLE则使能，DISABLE则不使能
 *
 * @return  无 
 */
static void timer_enable_cmd(uint32_t tim_n, EventStatus enable)
{
    if (ENABLE == enable)
    {
        timer_enable(tim_n);
    }
    else
    {
        timer_disable(tim_n);
    }
}

/***************************************************************************************************
 * @fn      bsp_pwm_output
 *
 * @brief   pwm输出 正相（P相）
 *
 * @param   gpio GPIO配置信息
 * @param   tim 定时器配置信息
 * @param   param pwm输出参数
 *
 * @return  无 
 */
void bsp_pwm_output(pwm_gpio_t *gpio, pwm_tim_t *tim, pwm_param_t *param)
{
    uint16_t period;
    uint16_t prescaler;
    uint32_t tim_n_clk;
    timer_parameter_struct time_base;
    timer_oc_parameter_struct time_oc_config;

    /* 开启定时器时钟 */
    rcu_periph_clock_enable(get_tim_rcc(tim->tim_n));

    if (param->duty_cycle == 0)
    {
        config_gpio_output(gpio);  /* 设置成推挽输出模式 */
        gpio_bit_reset(gpio->gpio_port, gpio->gpio_pin);  /* GPIO输出低电平 */
        timer_enable_cmd(tim->tim_n, tim->enable);  /* 定时器控制：是否要开启定时器 */

        return;
    }
    else if (param->duty_cycle == 10000)
    {
        config_gpio_output(gpio);  /* 设置成推挽输出模式 */
        gpio_bit_set(gpio->gpio_port, gpio->gpio_pin);  /* GPIO输出高电平 */
        timer_enable_cmd(tim->tim_n, tim->enable);  /* 定时器控制：是否要开启定时器 */

        return;
    }

    /* 定时器时钟频率 */
    if (TIMER0 == tim->tim_n || TIMER7 == tim->tim_n)
    {
        tim_n_clk = SystemCoreClock;
    }
    else
    {
        tim_n_clk = SystemCoreClock / 2;
    }

    /* 根据设置频率设置分频值 */
    if (param->freq < 100)
    {
        prescaler = 10000 - 1;  /* 分频比 = 10000 */
        period =  (tim_n_clk / 10000) / param->freq  - 1;  /* 自动重装的值 */
    }
    else if (param->freq < 3000)
    {
        prescaler = 100 - 1;  /* 分频比 = 100 */
        period =  (tim_n_clk / 100) / param->freq  - 1;  /* 自动重装的值 */
    }
    else	/* 大于4K的频率，无需分频 */
    {
        prescaler = 0;  /* 分频比 = 1 */
        period = tim_n_clk / param->freq - 1;  /* 自动重装的值 */
    }

    /* 配置PWM输出引脚的GPIO */
    config_gpio_pwm(gpio);

    /* 基本定时器配置 */
	time_base.prescaler         = prescaler;
    time_base.alignedmode       = TIMER_COUNTER_EDGE;
    time_base.counterdirection  = TIMER_COUNTER_UP;
    time_base.period            = period;
    time_base.clockdivision     = TIMER_CKDIV_DIV1;
    time_base.repetitioncounter = 0;
    timer_init(tim->tim_n, &time_base);

    /* 定时器OC配置 */
    timer_channel_output_struct_para_init(&time_oc_config);
    time_oc_config.ocpolarity   = TIMER_OC_POLARITY_HIGH;
    time_oc_config.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
    time_oc_config.outputstate  = TIMER_CCX_ENABLE;
    time_oc_config.outputnstate = TIMER_CCXN_DISABLE;
    time_oc_config.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
    time_oc_config.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
    timer_channel_output_config(tim->tim_n, tim->tim_ch, &time_oc_config);

    /* 设置比较器的值 */ 
    timer_channel_output_pulse_value_config(tim->tim_n, tim->tim_ch, (param->duty_cycle * period) / 10000);
    timer_channel_output_mode_config(tim->tim_n, tim->tim_ch, TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(tim->tim_n, tim->tim_ch, TIMER_OC_SHADOW_DISABLE);
    
    /* 开启自动重装载 */
    timer_auto_reload_shadow_enable(tim->tim_n);
    
    if (TIMER0 == tim->tim_n || TIMER7 == tim->tim_n)
    {
        timer_primary_output_config(tim->tim_n, ENABLE);
    }
    
    /* 定时器控制：是否要开启定时器 */
    timer_enable_cmd(tim->tim_n, tim->enable);
}

/***************************************************************************************************
 * @fn      bsp_pwm_output_n
 *
 * @brief   pwm输出 反相（N相）
 *
 * @param   gpio GPIO配置信息
 * @param   tim 定时器配置信息
 * @param   param pwm输出参数
 *
 * @return  无 
 */
void bsp_pwm_output_n(pwm_gpio_t *gpio, pwm_tim_t *tim, pwm_param_t *param)
{
    uint16_t period;
    uint16_t prescaler;
    uint32_t tim_n_clk;
    timer_parameter_struct time_base;
    timer_oc_parameter_struct time_oc_config;

    /* 开启定时器时钟 */
    rcu_periph_clock_enable(get_tim_rcc(tim->tim_n));

    if (param->duty_cycle == 0)
    {
        config_gpio_output(gpio);  /* 设置成推挽输出模式 */
        gpio_bit_reset(gpio->gpio_port, gpio->gpio_pin);  /* GPIO输出低电平 */
        timer_enable_cmd(tim->tim_n, tim->enable);  /* 定时器控制：是否要开启定时器 */

        return;
    }
    else if (param->duty_cycle == 10000)
    {
        config_gpio_output(gpio);  /* 设置成推挽输出模式 */
        gpio_bit_set(gpio->gpio_port, gpio->gpio_pin);  /* GPIO输出高电平 */
        timer_enable_cmd(tim->tim_n, tim->enable);  /* 定时器控制：是否要开启定时器 */

        return;
    }

    /* 定时器时钟频率 */
    if (TIMER0 == tim->tim_n || TIMER7 == tim->tim_n)
    {
        tim_n_clk = SystemCoreClock;
    }
    else
    {
        tim_n_clk = SystemCoreClock / 2;
    }

    /* 根据设置频率设置分频值 */
    if (param->freq < 100)
    {
        prescaler = 10000 - 1;  /* 分频比 = 10000 */
        period =  (tim_n_clk / 10000) / param->freq  - 1;  /* 自动重装的值 */
    }
    else if (param->freq < 3000)
    {
        prescaler = 100 - 1;  /* 分频比 = 100 */
        period =  (tim_n_clk / 100) / param->freq  - 1;  /* 自动重装的值 */
    }
    else	/* 大于4K的频率，无需分频 */
    {
        prescaler = 0;  /* 分频比 = 1 */
        period = tim_n_clk / param->freq - 1;  /* 自动重装的值 */
    }

    /* 配置PWM输出引脚的GPIO */
    config_gpio_pwm(gpio);

    /* 基本定时器配置 */
	time_base.prescaler         = prescaler;
    time_base.alignedmode       = TIMER_COUNTER_EDGE;
    time_base.counterdirection  = TIMER_COUNTER_UP;
    time_base.period            = period;
    time_base.clockdivision     = TIMER_CKDIV_DIV1;
    time_base.repetitioncounter = 0;
    timer_init(tim->tim_n, &time_base);

    /* 定时器OC配置 */
    timer_channel_output_struct_para_init(&time_oc_config);
    time_oc_config.ocpolarity   = TIMER_OC_POLARITY_HIGH;
    time_oc_config.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
    time_oc_config.outputstate  = TIMER_CCX_DISABLE;
    time_oc_config.outputnstate = TIMER_CCXN_ENABLE;
    time_oc_config.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
    time_oc_config.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
    timer_channel_output_config(tim->tim_n, tim->tim_ch, &time_oc_config);

    /* 设置比较器的值 */ 
    timer_channel_output_pulse_value_config(tim->tim_n, tim->tim_ch, (param->duty_cycle * period) / 10000);
    timer_channel_output_mode_config(tim->tim_n, tim->tim_ch, TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(tim->tim_n, tim->tim_ch, TIMER_OC_SHADOW_DISABLE);
    
    /* 开启自动重装载 */
    timer_auto_reload_shadow_enable(tim->tim_n);
    
    if (TIMER0 == tim->tim_n || TIMER7 == tim->tim_n)
    {
        timer_primary_output_config(tim->tim_n, ENABLE);
    }
    
    /* 定时器控制：是否要开启定时器 */
    timer_enable_cmd(tim->tim_n, tim->enable);
}
